package com.jar.springbootsecuritydemo.config;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jar.springbootsecuritydemo.mapper.SysMenuMapper;
import com.jar.springbootsecuritydemo.mapper.SysRoleMenuMapper;
import com.jar.springbootsecuritydemo.mapper.SysUserRoleMapper;
import com.jar.springbootsecuritydemo.pojo.bo.SecurityUser;
import com.jar.springbootsecuritydemo.pojo.entity.SysMenu;
import com.jar.springbootsecuritydemo.pojo.entity.SysRoleMenu;
import com.jar.springbootsecuritydemo.pojo.entity.SysUser;
import com.jar.springbootsecuritydemo.pojo.entity.SysUserRole;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 自定义权限注解验证
 */
@Configuration
public class AuthorizationEvaluator implements PermissionEvaluator {
 
    @Resource
    private SysMenuMapper sysMenuMapper;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    /**
     * hasPermission鉴权方法
     * 这里仅仅判断PreAuthorize注解中的权限表达式
     * 实际中可以根据业务需求设计数据库通过targetUrl和permission做更复杂鉴权
     *
     * @Param authentication  用户身份
     * @Param targetUrl  请求路径
     * @Param permission 请求路径权限
     * @Return boolean 是否通过
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) {
        //获取用户信息
        SecurityUser selfUserEntity = (SecurityUser) authentication.getPrincipal();
        // 查询用户权限(这里可以将权限放入缓存中提升效率)
        Set<String> permissions = new HashSet<>();

        List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectList(
                new QueryWrapper<SysUserRole>().eq(SysUser.COL_USER_ID, selfUserEntity.getUid())
        );

        List<Integer> roleIds = sysUserRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());

        List<SysRoleMenu> sysRoleMenus = sysRoleMenuMapper.selectList(
                new QueryWrapper<SysRoleMenu>().in(SysRoleMenu.COL_ROLE_ID, roleIds)
        );

        List<Integer> menuIds = sysRoleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());


        List<SysMenu> sysMenus = sysMenuMapper.selectBatchIds(menuIds);
        for (SysMenu sysMenu : sysMenus) {
            permissions.add(sysMenu.getPerms());
        }
        // 权限对比
        if (permissions.contains(permission.toString())) {
            return true;
        }
        return false;
    }
 
    /**
     * Alternative method for evaluating a permission where only the identifier of the
     * target object is available, rather than the target instance itself.
     *
     * @param authentication represents the user in question. Should not be null.
     * @param targetId       the identifier for the object instance (usually a Long)
     * @param targetType     a String representing the target's type (usually a Java
     *                       classname). Not null.
     * @param permission     a representation of the permission object as supplied by the
     *                       expression system. Not null.
     * @return true if the permission is granted, false otherwise
     */
    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        return false;
    }
}